\subsection{Таблица \TT{V\$TIMER} в \oracle}
\myindex{\oracle}

\TT{V\$TIMER} это еще один служебный \IT{fixed view}, отражающий какое-то часто меняющееся значение:

\begin{framed}
\begin{quotation}
V\$TIMER displays the elapsed time in hundredths of a second. Time is measured since the beginning of the epoch, 
which is operating system specific, and wraps around to 0 again whenever the value overflows four bytes 
(roughly 497 days).
\end{quotation}
\end{framed}(Из документации \oracle
\footnote{\url{http://go.yurichev.com/17088}})

Интересно что периоды разные в Oracle для Win32 и для Linux. Сможем ли мы найти функцию, отвечающую 
за генерирование этого значения?

Как видно, эта информация, в итоге, берется из системной таблицы \TT{X\$KSUTM}.

\begin{lstlisting}
SQL> select * from V$FIXED_VIEW_DEFINITION where view_name='V$TIMER';

VIEW_NAME
------------------------------
VIEW_DEFINITION
------------------------------

V$TIMER
select  HSECS from GV$TIMER where inst_id = USERENV('Instance')

SQL> select * from V$FIXED_VIEW_DEFINITION where view_name='GV$TIMER';

VIEW_NAME
------------------------------
VIEW_DEFINITION
------------------------------

GV$TIMER
select inst_id,ksutmtim from x$ksutm
\end{lstlisting}

Здесь мы упираемся в небольшую проблему, в таблицах \TT{kqftab}/\TT{kqftap} нет указателей на функцию, 
которая бы генерировала значение:

\begin{lstlisting}[caption=Результат работы \OracleTablesName]
kqftab_element.name: [X$KSUTM] ?: [ksutm] 0x1 0x4 0x4 0x0 0xffffc09b 0x3
kqftap_param.name=[ADDR] ?: 0x10917 0x0 0x0 0x0 0x4 0x0 0x0
kqftap_param.name=[INDX] ?: 0x20b02 0x0 0x0 0x0 0x4 0x0 0x0
kqftap_param.name=[INST_ID] ?: 0xb02 0x0 0x0 0x0 0x4 0x0 0x0
kqftap_param.name=[KSUTMTIM] ?: 0x1302 0x0 0x0 0x0 0x4 0x0 0x1e
kqftap_element.fn1=NULL
kqftap_element.fn2=NULL
\end{lstlisting}

Попробуем в таком случае просто поискать строку \TT{KSUTMTIM}, и находим ссылку на нее в такой функции:

\begin{lstlisting}[style=customasmx86]
kqfd_DRN_ksutm_c proc near    ; DATA XREF: .rodata:0805B4E8

arg_0   = dword ptr  8
arg_8   = dword ptr  10h
arg_C   = dword ptr  14h

        push    ebp
        mov     ebp, esp
        push    [ebp+arg_C]
        push    offset ksugtm
        push    offset _2__STRING_1263_0 ; "KSUTMTIM"
        push    [ebp+arg_8]
        push    [ebp+arg_0]
        call    kqfd_cfui_drain
        add     esp, 14h
        mov     esp, ebp
        pop     ebp
        retn
kqfd_DRN_ksutm_c endp
\end{lstlisting}

Сама функция \TT{kqfd\_DRN\_ksutm\_c()} упоминается в таблице \\
\TT{kqfd\_tab\_registry\_0} вот так:

\begin{lstlisting}[style=customasmx86]
dd offset _2__STRING_62_0 ; "X$KSUTM"
dd offset kqfd_OPN_ksutm_c
dd offset kqfd_tabl_fetch
dd 0
dd 0
dd offset kqfd_DRN_ksutm_c
\end{lstlisting}

Упоминается также некая функция \TT{ksugtm()}.
Посмотрим, что там (в Linux x86):

\begin{lstlisting}[caption=ksu.o,style=customasmx86]
ksugtm  proc near

var_1C  = byte ptr -1Ch
arg_4   = dword ptr  0Ch

        push    ebp
        mov     ebp, esp
        sub     esp, 1Ch
        lea     eax, [ebp+var_1C]
        push    eax
        call    slgcs
        pop     ecx
        mov     edx, [ebp+arg_4]
        mov     [edx], eax
        mov     eax, 4
        mov     esp, ebp
        pop     ebp
        retn
ksugtm  endp
\end{lstlisting}

В win32-версии тоже самое.

Искомая ли эта функция? Попробуем узнать:
\myindex{tracer}

\begin{lstlisting}
tracer -a:oracle.exe bpf=oracle.exe!_ksugtm,args:2,dump_args:0x4
\end{lstlisting}

Пробуем несколько раз:

\begin{lstlisting}
SQL> select * from V$TIMER;

     HSECS
----------
  27294929

SQL> select * from V$TIMER;

     HSECS
----------
  27295006

SQL> select * from V$TIMER;

     HSECS
----------
  27295167
\end{lstlisting}

\begin{lstlisting}[caption=вывод \tracer]
TID=2428|(0) oracle.exe!_ksugtm (0x0, 0xd76c5f0) (called from oracle.exe!__VInfreq__qerfxFetch+0xfad (0x56bb6d5))
Argument 2/2
0D76C5F0: 38 C9                                           "8.              "
TID=2428|(0) oracle.exe!_ksugtm () -> 0x4 (0x4)
Argument 2/2 difference
00000000: D1 7C A0 01                                     ".|..            "
TID=2428|(0) oracle.exe!_ksugtm (0x0, 0xd76c5f0) (called from oracle.exe!__VInfreq__qerfxFetch+0xfad (0x56bb6d5))
Argument 2/2
0D76C5F0: 38 C9                                           "8.              "
TID=2428|(0) oracle.exe!_ksugtm () -> 0x4 (0x4)
Argument 2/2 difference
00000000: 1E 7D A0 01                                     ".}..            "
TID=2428|(0) oracle.exe!_ksugtm (0x0, 0xd76c5f0) (called from oracle.exe!__VInfreq__qerfxFetch+0xfad (0x56bb6d5))
Argument 2/2
0D76C5F0: 38 C9                                           "8.              "
TID=2428|(0) oracle.exe!_ksugtm () -> 0x4 (0x4)
Argument 2/2 difference
00000000: BF 7D A0 01                                     ".}..            "
\end{lstlisting}

Действительно --- значение то, что мы видим в SQL*Plus, и оно возвращается через второй аргумент.

Посмотрим, что в функции \TT{slgcs()} (Linux x86):

\begin{lstlisting}[style=customasmx86]
slgcs   proc near

var_4   = dword ptr -4
arg_0   = dword ptr  8

        push    ebp
        mov     ebp, esp
        push    esi
        mov     [ebp+var_4], ebx
        mov     eax, [ebp+arg_0]
        call    $+5
        pop     ebx
        nop                     ; PIC mode
        mov     ebx, offset _GLOBAL_OFFSET_TABLE_
        mov     dword ptr [eax], 0
        call    sltrgatime64    ; PIC mode
        push    0
        push    0Ah
        push    edx
        push    eax
        call    __udivdi3       ; PIC mode
        mov     ebx, [ebp+var_4]
        add     esp, 10h
        mov     esp, ebp
        pop     ebp
        retn
slgcs   endp
\end{lstlisting}

(это просто вызов \TT{sltrgatime64()} и деление его результата на 10 (\myref{sec:divisionbymult}))

И в win32-версии:

\begin{lstlisting}[style=customasmx86]
_slgcs  proc near     ; CODE XREF: _dbgefgHtElResetCount+15
                      ; _dbgerRunActions+1528
        db      66h
        nop
        push    ebp
        mov     ebp, esp
        mov     eax, [ebp+8]
        mov     dword ptr [eax], 0
        call    ds:__imp__GetTickCount@0 ; GetTickCount()
        mov     edx, eax
        mov     eax, 0CCCCCCCDh
        mul     edx
        shr     edx, 3
        mov     eax, edx
        mov     esp, ebp
        pop     ebp
        retn
_slgcs  endp
\end{lstlisting}

Это просто результат \TT{GetTickCount()}
\footnote{\href{http://go.yurichev.com/17248}{MSDN}}
поделенный на 10 (\myref{sec:divisionbymult}).

Вуаля! Вот почему в win32-версии и версии Linux x86 разные результаты, потому что они получаются разными 
системными функциями \ac{OS}.

\IT{Drain} по-английски \IT{дренаж, отток, водосток}. Таким образом, возможно имеется ввиду \IT{подключение} 
определенного столбца системной таблице к функции.

Добавим поддержку таблицы \TT{kqfd\_tab\_registry\_0} в \oracletables, 
теперь мы можем видеть, при помощи каких функций, столбцы в системных таблицах \IT{подключаются} к значениям, 
например:

\begin{lstlisting}
[X$KSUTM] [kqfd_OPN_ksutm_c] [kqfd_tabl_fetch] [NULL] [NULL] [kqfd_DRN_ksutm_c]
[X$KSUSGIF] [kqfd_OPN_ksusg_c] [kqfd_tabl_fetch] [NULL] [NULL] [kqfd_DRN_ksusg_c]
\end{lstlisting}

\IT{OPN}, возможно, \IT{open}, а \IT{DRN}, вероятно, означает \IT{drain}.

